
#include <iostream>
#include <string>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
#include <cstring>
#include "Task.hpp"
#include <sys/wait.h>

// 形参类型和命名规范:
// & : 表示输入输出型参数
// const & : 表示输入型参数
// cosnt * : 表示输出型参数

// master 视角
// 先描述管道（一种通信信道）
class Channel // 信道，即管道
{
public:
    Channel(int wfd, pid_t id, const std::string &name)
        : _wfd(wfd), _subProcessId(id), _name(name)
    {
    }
    ~Channel() {}
    int GetWfd() const { return _wfd; }
    int GetSubProcessId() const { return _subProcessId; }
    std::string Getname() const { return _name; }
    void CloseChannel() { close(_wfd); }
    void Wait()
    {
        pid_t rid = waitpid(_subProcessId, nullptr, 0);
        if (rid > 0)
            std::cout << "Wait " << rid << "success, name is " << _name << std::endl;
    }

private:
    int _wfd;            // 写文件描述符
    pid_t _subProcessId; // 子进程 ID
    std::string _name;   // 管道名称，方便打印消息
};

// void work(int rfd)
// {
//     while (true)
//     {
//         int command = 0;
//         int n = read(rfd, &command, sizeof(command));
//         if (n == sizeof(int))
//         {
//             std::cout << "The pid is " << getpid() << " handler task" << std::endl;
//             ExcuteTask(command);
//         }
//         else if (n == 0)
//         {
//             std::cout << "sub process: " << getpid() << " quit" << std::endl;
//             break;
//         }
//     }
// }


void PrintProcess(const std::vector<Channel> &channels)
{
    for (auto &e : channels)
    {
        std::cout << "********************************************" << std::endl;
        std::cout << "name: " << e.Getname() << ", id: " << e.GetSubProcessId()
                  << ", wfd: " << e.GetWfd() << std::endl;
    }
}

void CreateChannelAndSub(std::vector<Channel> *channels, int num, task_t task)
{
    for (int i = 0; i < num; ++i)
    {
        // 创建管道
        int pipefd[2] = {0};
        int n = pipe(pipefd);
        if (n < 0)
        {
            std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;
            exit(1);
        }

        // 创建子进程
        pid_t id = fork();
        if (id == 0)
        {
            if (!channels->empty())
                for (auto& e: *channels)
                    e.CloseChannel();
            // child - read
            close(pipefd[1]);
            dup2(pipefd[0], 0); // 重定向
            task();
            close(pipefd[0]);
            exit(0);
        }

        // parent - write
        close(pipefd[0]);
        // 构建管道名字
        std::string channel_name = "Channel - " + std::to_string(i);
        // 子进程 pid 已经有了，父进程的写端也已经有了
        // 随后使用 Channel 来统一管理，插入即可
        channels->push_back(Channel(pipefd[1], id, channel_name));
    }
}

int NextChannel(int num)
{
    static int next = 0;
    int channel = next;
    ++next;
    channel %= num;
    return channel;
}

void SendTaskCommand(const Channel &channel, int taskcommand)
{
    write(channel.GetWfd(), &taskcommand, sizeof(taskcommand));
}

void ControlProcessOnce(const std::vector<Channel> &channels)
{
    sleep(1);
    // 选择一个任务
    int taskcommand = SelectTask();
    // 选择一个信道（子进程）
    int channel_index = NextChannel(channels.size());
    // 发送任务
    SendTaskCommand(channels[channel_index], taskcommand);

    std::cout << "这是 " << taskcommand << " 号任务，被名为 " << channels[channel_index].Getname()
              << " 的子进程执行！ id 为 " << channels[channel_index].GetSubProcessId() << std::endl;
}

void ControlProcess(const std::vector<Channel> &channels, int times = -1)
{
    if (times > 0)
        while (times--)
            ControlProcessOnce(channels);
    else
        while (true)
            ControlProcessOnce(channels);
}

void CleanUpChannels(std::vector<Channel> &channels)
{
    // int num = channels.size() - 1;
    // while (num >= 0)
    // {
    //     channels[num].CloseChannel();
    //     channels[num--].Wait();
    // }

    for (auto &e : channels)
    {
        // 关闭写端
        e.CloseChannel();
        // 回收子进程
        e.Wait();
    }

    // for (auto &e : channels)
    // {
    //     // 关闭写端
    //     e.CloseChannel();
    // }
    // for (auto &e : channels)
    // {
    //     // 回收子进程
    //     e.Wait();
    // }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << argv[0] << " processnum" << std::endl;
        return 1;
    }
    int num = std::stoi(argv[1]);

    // 加载任务
    LoadTask();

    // 定义信道（管道）组织方式
    std::vector<Channel> channels;

    // 创建信道（管道）和子进程
    CreateChannelAndSub(&channels, num, work);

    // 通过 channels 控制子进程
    ControlProcess(channels, 10);

    // 回收信道（管道）和子进程
    CleanUpChannels(channels);


    // PrintProcess(channels);
    // sleep(500);

    return 0;
}
